//解析模块

export class IapNode {
    tag: string = "";
    attrs: { [x: string]: string} = {};
    children: IapNode[] = [];

    setAttr(key: string, value: string) {
        this.attrs[key] = value;
    }

    hasAttr(key: string) {
        return Object.prototype.hasOwnProperty.call(this.attrs, key)
    }
    
    getAttr(...keys: string[]) : string | undefined {
        for (let _k of keys) {
            if(this.attrs[_k] !== undefined && this.attrs[_k] !== null) {
                return this.attrs[_k];
            }
        }
        return undefined;
    }

    numberAttrOrDefault(key: string, defaultValue: number) : number {
        if(this.getAttr(key)) {
            try {
                var value = this.getAttr(key)
                if(value) {
                    return parseFloat(value)
                }
            }
            catch(_) {}
        }
        return defaultValue;
    }

    numberAttr(...keys: string[]) : number | undefined {
        var value = this.getAttr(...keys)
        if(value) {
            try {
                return parseFloat(value)
            }
            catch(_) {}
        }
        return undefined;
    }

    deleteAttr(key: string) {
        delete this.attrs[key];
    }

    boolAttr(...keys: string[]) : boolean {
        for (let key of keys) {
            if(this.hasAttr(key)) {
                return this.getAttr(key) != "false"
            }
            else if(this.hasAttr("!"+key)){
                return false;
            }
        }
        return false;
    }

    arrayAttr(...keys: string[]) : string[] | undefined {
        for (let key of keys) {
            if(key != undefined) {
                var value = this.attrs[key];
                if(value) {
                    return value.split(",");
                }
            }
        }
        return undefined;
    }

    findByTab(tag: string): IapNode[] {
        return this.children.filter(t=>t.tag == tag);
    }

    /** 深度foreach 包含自己 */
    depthForEach(callbackFn: (node : IapNode)=>void) {
        callbackFn(this);
        for (let child of this.children) {
            child.depthForEach(callbackFn);
        }
    }
}


export function parse (str: string) : IapNode {
    return new ParseClass(str).parse();
}

export class ParseClass {
    static InvalidChar = [' ', "\r\n", "\n", "\u00a0" , "\t", '[', ']', '=', '{', "}", "/]"];
    static spaceChar = [' ', "\r\n", "\n" , "\t", "\u00a0"];
    // index: number = -1;
    nextIndex: number = 0;
    // lastIndex: number = -1;
    parseStr: string = '';
    // matchStr: string = '';
    count = 200;

    /** 阻止继续搜索的字符串 */
    holdStr: string = '';
    tempStr: string = "";

    error: boolean = false;

    constructor(parseStr: string) {
        this.parseStr = parseStr;
    }

    isMatchIap() : boolean {
        let flag = false;
        this.skipSpace();
        if(this.isNextStr("[:IAP")) {
            flag = true;
        }
        this.nextIndex = 0;
        return flag;
    }


    parse() : IapNode {
        var state = 0; //模式 0:搜索[ 1:搜索开标签]或结束标签/]  2:搜索结束标签[/模式, 3:搜索结束标签]
        var node = new IapNode();
        // return null;
        while (true) {
            switch (state) {
                case 0:
                    {
                        //标签头检查
                        this.skipSpace();
                        if (this.isNextStr("[") && !this.isNextStr("[/")) {
                            this.skip(1);
                            this.skipSpace();
                            if (this.nextValidStr()) {
                                node.tag = this.tempStr;
                                this.skipSpace();
                                if (this.isNextStr("/]")) {
                                    this.skip(2);
                                    state = 99;
                                }
                                else if(this.isNextStr("]")) {
                                    this.skip(1);
                                    state = 2;
                                }
                                else {
                                    state = 1;
                                }
                            }
                            else {
                                this.error = true;
                            }
                        }
                        else {
                            this.error = true;
                        }
                    }
                    break;
                case 1:
                    {
                        var key ="";
                        var value = "";
                        //属性检查
                        this.skipSpace();
                        
                        if(this.isNextStr("]")) {
                            this.skip(1);
                            state = 2;
                        }
                        else if (this.isNextStr("/]")){
                            this.skip(2);
                            state = 99;
                        }
                        else if (this.nextValidStr()) {
                            key = this.tempStr;
                            this.skipSpace();
                            if(this.isNextStr("=")) {
                                this.skip(1);
                                this.skipSpace();
                                if(this.isNextStr("{")) {
                                    this.skip(1);
                                    if (this.subNextString("}")) {
                                        value = this.tempStr;
                                        // state = 3;
                                    }else {
                                        //报错
                                        this.error = true;
                                    }
                                }
                                else {
                                    if (this.nextValidStr()) {
                                        value = this.tempStr;
                                    }
                                    else {
                                        this.error = true;
                                    }
                                }
                            }
                            node.setAttr(key, value);
                        }else {
                            this.error = true;
                        }
                    }
                    break;
                case 2:
                    {
                        //标签子元素解析
                        a: while(true) {
                            this.skipSpace();
                            if(this.isNextStr("[/")) {
                                state = 3;
                                break a;
                            }
                            else {
                                node.children.push(this.parse())
                            }
                        }
                    }
                    break;
                case 3: {
                        this.skipSpace();
                        if(this.isNextStr("[/")) {
                            this.skip(2);
                            this.subNextString("]");
                            state = 99;
                        }
                    }break;
                case 99: return node; 
            }

            if (this.error) {
                var startIndex = Math.max(0, this.nextIndex -5)
                var endIndex = Math.min(this.parseStr.length, this.nextIndex+5)
                throw new Error(`解析失败，在处理阶段${state}的${this.parseStr.substring(startIndex,this.nextIndex)}|${this.parseStr.substring(this.nextIndex, endIndex)}附近`);
            }
        }
    }

    /**
     * 截取到下一个字符串
     * @param nextString 
     * @returns 
     */
     private subNextString(nextString: string): boolean {
        var startIndex = this.nextIndex;
        var index = this.parseStr.indexOf(nextString, startIndex);
        if(index != -1) {
            this.tempStr = this.parseStr.substring(startIndex, index);
            this.nextIndex = index + nextString.length;
            return true;
        }
        else {
            return false;
        }
    }

    private nextValidStr() : boolean {
        var flag = false;
        // this.lastIndex = this.nextIndex;
        var startIndex = this.nextIndex;
        while(true) {
            // var char = this.parseStr.charAt(this.nextIndex);
            for (let item of ParseClass.InvalidChar) {
                if (this.parseStr.startsWith(item, this.nextIndex)) {
                    this.holdStr = item;
                    this.tempStr =  this.subString(startIndex, this.nextIndex);
                    return flag;
                }
            }
            flag = true;
            this.nextIndex ++;
        }
    }

    private isNextStr(str: string) : boolean {
        return this.parseStr.startsWith(str, this.nextIndex);
    }

    private skip(num: number) {
        this.nextIndex += num;
    }

    private skipSpace() : boolean {
        var flag = false;
        while(true) {
            //跳过空格
            
            if(ParseClass.spaceChar.findIndex(t=> this.parseStr.startsWith(t, this.nextIndex)) != -1) {
                this.nextIndex ++;
                flag = true;
            }
            else {
                return flag;
            }
        }
    }

    private subString(start: number, end: number): string {
        return this.parseStr.substring(start, end);
    }
}
